package com.xuanwu.ai.flow.component.persistence;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xuanwu.ai.core.utils.IdWorker;
import com.xuanwu.ai.flow._enum.CmpTypeEnum;
import com.xuanwu.ai.flow.mapper.ComponentMapper;
import com.xuanwu.ai.flow.model.AIComponent;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;

import java.util.*;

@Slf4j
@Component
public class CmpRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware, CommandLineRunner {

    private ResourceLoader resourceLoader;

    private Environment environment;

    static private List<AIComponent> cmpList = new ArrayList<>();

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ComponentMapper componentMapper;


    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }


    @Override
    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    @SneakyThrows
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        // 创建scanner
        ClassPathScanningCandidateComponentProvider scanner = getScanner();
        scanner.setResourceLoader(resourceLoader);

        // 设置扫描器scanner扫描的过滤条件
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(LiteflowComponent.class);
        scanner.addIncludeFilter(annotationTypeFilter);

        // 获取指定要扫描的basePackages
        Set<String> basePackages = getBasePackages(metadata);

        for (String basePackage : basePackages) {
            // 通过scanner获取basePackage下的候选类(有标@LiteflowComponent注解的类)
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition) {
                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;
                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
                    // 获取@LiteflowComponent注解的属性
                    Map<String, Object> attributes = annotationMetadata.getAnnotationAttributes(LiteflowComponent.class.getCanonicalName());
                    //获取全路径类名
                    String beanClassName = beanDefinition.getBeanClassName();
                    Class<?> cmpClass = Class.forName(beanClassName);

                    AIComponent aiComponent = new AIComponent();
                    aiComponent.setName((String) attributes.get("value"));
                    aiComponent.setDescription((String) attributes.get("name"));
                    aiComponent.setType(CmpTypeEnum.getCmpType(cmpClass.getSuperclass().getSimpleName()));
                    aiComponent.setClasspath(beanClassName);
                    cmpList.add(aiComponent);
                }
            }
        }
    }

    private Set<String> getBasePackages(AnnotationMetadata metadata) {
        // 获取到@CmpScan注解所有属性
        Map<String, Object> attributes = metadata.getAnnotationAttributes(CmpScan.class.getCanonicalName());
        Set<String> basePackages = new HashSet<>();
        assert attributes != null;

        // basePackages 属性是否有配置值，如果有则添加
        for (String pkg : (String[]) attributes.get("basePackages")) {
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }

        // 如果上面没有获取到basePackages，那么这里就默认使用当前项目启动类所在的包为basePackages
        if (basePackages.isEmpty()) {
            basePackages.add(ClassUtils.getPackageName(metadata.getClassName()));
        }

        return basePackages;
    }

    /**
     * 创建扫描器
     */
    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent()) {
                    //是类或者接口
                    if (!beanDefinition.getMetadata().isAnnotation()) {
                        isCandidate = true;
                    }
                }
                return isCandidate;
            }
        };
    }

    @Override
    public void run(String... args) throws Exception {
        //删除旧的组件
        componentMapper.delete(Wrappers.emptyWrapper());

        cmpList.forEach(cmp -> {
            cmp.setId(idWorker.genId());
            Date date = new Date();
            cmp.setCreateTime(date);
            cmp.setUpdateTime(date);
            componentMapper.insert(cmp);
        });

        cmpList = null;
    }
}
